import { StrTool } from './StrTool'

/**
 * NumberTool
 * @author 冰凝
 * @date 2022-09-19 09:42:40
 **/
export class NumberTool {

    /**
     * 以货币形式展示数字 <br>
     * @param amount 待显示金额
     * @param fraction 小数位数, 默认 2
     * @param interval 间隔 默认 4
     * @param locale 货币标识 默认 ￥
     */
    public static showAmount(
        amount: string | number,
        fraction: number = 2,
        interval: number = 4,
        locale: string = '￥ ',
    ): string {
        return locale + NumberTool.show(amount, fraction, interval)
    }

    /**
     * 展示一个数字 使用指定的分隔位和小数位数
     * @param num 要展示的数字
     * @param fraction 小数位数 大于等于零
     * @param interval 分隔位 大于等于一
     */
    public static show(
        num: string | number,
        fraction: number = 2,
        interval: number = 4,
    ): string {
        const show = (numStr: string) => {
            let [ integer, decimal = '' ] = numStr.split(StrTool.DO)

            // 移除负号, 避免位数判断错误
            let isNegative = false
            if (parseFloat(integer!) < 0) {
                integer = integer!.substring(1)
                isNegative = true
            }

            const show: Array<string> = []
            let count = 0
            for (let i = integer!.length - 1; i >= 0; i--) {
                const charAt = integer!.charAt(i)
                count++
                if (count % interval === 0 && count !== integer!.length) {
                    show.unshift(', ' + charAt)
                } else {
                    show.unshift(charAt)
                }
            }

            const s = fraction > 0
                ? show.join(StrTool.EMPTY) + StrTool.DO + decimal
                : show.join(StrTool.EMPTY)

            return isNegative ? '-' + s : s
        }

        if (typeof num === 'number') {
            return show(num.toFixed(fraction))
        }

        // typeof amount === 'string'
        return show(parseFloat(num).toFixed(fraction))
    }

    /**
     * 数值边界限制
     * @param num 待处理数字
     * @param min 最小值(含)
     * @param max 最大值 (含)
     */
    public static limit(num: number, min = 0, max = 9999_9999_9999): number {
        return Math.max(Math.min(num, max), min)
    }

    /**
     * 指定数字范围转范围内所有数组成的数组, 步进1 <br>
     * 范围:
     * - 对于整数 恰好是 [start, end];
     * - 对于小数 从 start, 开始按照步长增长到最后一个 小于等于 end 的数字
     *
     * @param start 开始范围, 允许大于 end
     * @param end 结束范围, 允许小于 start
     */
    public static range(start: number, end: number): Array<number> {
        const res: Array<number> = []
        const max = Math.max(start, end)
        const min = Math.min(start, end)
        for (let i = min; i <= max; i++) {
            res.push(i)
        }
        return res
    }
}
